const { resolve, relative } = require('path');
const _ = require('lodash');
const { filterMode, getModeShortName } = require('./utils/runtimeMode');
const isDir = require('./utils/isDir');
const loadJson = require('./utils/loadJson');
const deepMerge = require('./utils/deepMerge');
const filterExistFiles = require('./utils/filterExistFiles');

/**
 *
 * @param {string} projectName 项目名称
 * @param {string} projectRoot 项目根目录
 * @param {{makeOutputDir: function, makeOutputPath: function}} options 自定义配置
 * @param {{}} mergeConfig 附加的配置信息
 */
function taroConfig(projectName, projectRoot, options, mergeConfig) {
  /**
   * 执行时的目录
   * @type {string}
   */
  const cwd = process.cwd();
  /**
   * 环境变量
   */
  const {
          NODE_ENV,
          TARO_ENV  : taroEnv,
          CUSTOM_ENV: customEnv,
        } = process.env;
  /**
   * 运行模式
   * @type {string}
   */
  const mode = filterMode(NODE_ENV);
  const isDevel = mode === 'development';
  /**
   * 运行模式的短名称
   * @type {string}
   */
  const modeShortName = getModeShortName(mode);

  const ctx = {
    projectName, projectRoot,
    mode, modeShortName,
    taroEnv, customEnv,
  };

  const { makeOutputDir, makeOutputPath, makeConfigFiles } = options || {};

  if (!isDir(projectRoot)) {
    throw new Error(`项目目录不存在！`);
  }

  const projectInfoFile = resolve(projectRoot, 'package.json');
  const projectInfo = loadJson(projectInfoFile);

  if (projectInfo === false) {
    throw new Error(`项目的 package.json 不存在，或该文件内容无效或为空！`);
  }

  if (!projectInfo.name || !projectInfo.version) {
    throw new Error(`项目的 package.json 的 "name" 或 "version" 字段内容为空！`);
  }

  /**
   * 输出的目录名
   * @type {string}
   */
  let outputDir = `${projectName}-${taroEnv}`;
  if (customEnv !== '') {
    outputDir += `-${customEnv}`;
  }

  if (typeof makeOutputDir === 'function') {
    const customOutputDir = makeOutputDir(Object.assign({}, ctx, { outputDir }));
    if (_.isString(customOutputDir) && customOutputDir !== '') {
      outputDir = customOutputDir;
    }
  }

  /**
   * 项目输出的完整路径
   * @type {string}
   */
  let outputPath = '';
  if (isDevel) {
    outputPath = resolve(cwd, `./dist/${outputDir}`);
  } else {
    outputPath = resolve(cwd, `./release/${outputDir}/v${projectInfo.version}`);
  }

  if (typeof makeOutputPath === 'function') {
    const customOutputPath = makeOutputPath(Object.assign({}, ctx, { outputDir, outputPath }));
    if (_.isString(customOutputPath) && customOutputPath !== '') {
      outputPath = customOutputPath;
    }
  }

  const date    = new Date(),
        dateStr = `${date.getFullYear()}-${(date.getMonth() + 1)}-${date.getDate()}`;

  /**
   * 项目的源代码，Taro 必须是 src
   * @type {string}
   */
  const projectSrc = resolve(projectRoot, 'src');

  const configSrc    = relative(cwd, projectSrc),
        configOutput = relative(cwd, outputPath);

  const baseConfig = {
    projectName,
    date           : dateStr,
    designWidth    : 750,
    deviceRatio    : {
      640: 2.34 / 2,
      750: 1,
      828: 1.81 / 2
    },
    sourceRoot     : configSrc,
    outputRoot     : configOutput,
    plugins        : [],
    defineConstants: {
      AppName   : JSON.stringify(projectInfo.name),
      AppVersion: JSON.stringify(projectInfo.version),
      AppMode   : JSON.stringify(mode),
      AppCustom : JSON.stringify(customEnv),
    },
    copy           : {
      patterns: [],
      options : {}
    },
    framework      : 'react',
    mini           : {
      postcss: {
        pxtransform: {
          enable: true,
          config: {}
        },
        url        : {
          enable: true,
          config: {
            limit: 1024 // 设定转换尺寸上限
          }
        },
        cssModules : {
          enable: false, // 默认为 false，如需使用 css modules 功能，则设为 true
          config: {
            namingPattern     : 'module', // 转换模式，取值为 global/module
            generateScopedName: '[name]__[local]___[hash:base64:5]'
          }
        }
      }
    },
    h5             : {
      publicPath     : '/',
      staticDirectory: 'static',
      postcss        : {
        autoprefixer: {
          enable: true,
          config: {}
        },
        cssModules  : {
          enable: false, // 默认为 false，如需使用 css modules 功能，则设为 true
          config: {
            namingPattern     : 'module', // 转换模式，取值为 global/module
            generateScopedName: '[name]__[local]___[hash:base64:5]'
          }
        }
      }
    }
  };

  const mergeOption = { arrayMode: 'replace' };
  let config = deepMerge(baseConfig, mergeConfig || {}, mergeOption);

  const projectConfigFiles = [];
  if (customEnv !== '') {
    projectConfigFiles.push(resolve(projectRoot, `config/${modeShortName}.${customEnv}.js`));
  }
  projectConfigFiles.push(resolve(projectRoot, `config/${modeShortName}.js`));

  if (typeof makeConfigFiles === 'function') {
    makeConfigFiles(projectConfigFiles, ctx);
  }

  const files = filterExistFiles(projectConfigFiles);
  if (files.length > 0) {
    const loadConfig = require(files[0]);
    if (typeof loadConfig === 'function') {
      return deepMerge(config, loadConfig(config, ctx), mergeOption);
    }
    return deepMerge(config, loadConfig || {}, mergeOption);
  }

  return config;
}

module.exports = taroConfig;